use std::cell::{Cell, RefCell};

use std::ops::Sub;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, AtomicI16, AtomicU64, AtomicUsize, Ordering};
use std::sync::mpsc::{Receiver, Sender};
use std::sync::{Arc, Barrier, Condvar, Mutex, MutexGuard, Once, RwLock, RwLockWriteGuard, mpsc};
use std::time::{Duration, Instant};
use std::{hint, thread, vec};
use thread_local::ThreadLocal; //单线程指针

/*


多线程
竞态条件(race conditions)，多个线程以非一致性的顺序同时访问数据资源

死锁(deadlocks)，两个线程都想使用某个资源，但是又都在等待对方释放资源后才能使用，结果最终都无法继续执行

一些因为多线程导致的很隐晦的 BUG，难以复现和解决

use std::thread; 标准库

  thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });


*/

///开启一个线程
pub fn run1() {
    let th = thread::spawn(|| {
        for i in 1..10 {
            println!("线程输出{}", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    th.join().unwrap();
    for i in 1..5 {
        println!("普通输出{}", i);
        thread::sleep(Duration::from_millis(1));
    }
}

///move 关键字
///
///闭包 线程内可以使用外部 变量内容
///
///move 关键字 可以向外获取 外部环境都某个值（数据或内存地址）的所有权，当当前线程获取到所有权后，所有权在原本的作用域会失效
pub fn run2() {
    let a = vec![1, 2, 3, 4, 5];
    thread::spawn(move || {
        println!("Here's a vector: {:?}", a);
    })
    .join()
    .unwrap();
    //此时所有权已经转移到线程中，所以现在无法访问 数组a
    //println!("{}",a)

    let b = vec![1, 2, 3, 4, 5];
    thread::spawn(move || {
        println!("Here's a vector: {:?}", &b);
    })
    .join()
    .unwrap();

    //println!("{}",b)

    /*
    由于 i32 类型的数据 时存放在 栈上的并且 他们都是 长度确定的
    所以 当他们 发送所有权转移的时候 实际上时将 自身再复制一份 到特定区域，
    所以 这种在内存中长度确定的 数据类型 在所有权发生转移后原数据仍然能够使用
    */
    let c = 66;
    thread::spawn(move || {
        println!("Here's a num: {:?}", c);
    })
    .join()
    .unwrap();
    println!("{}", c);

    let d = 66;
    thread::spawn(move || {
        println!("Here's a num: {:?}", &d);
    })
    .join()
    .unwrap();
    println!("{}", d);
}

pub fn run3() {
    // 创建一个线程A
    let new_thread = thread::spawn(move || {
        // 再创建一个线程B
        thread::spawn(move || {
            loop {
                println!("I am a new thread.");
            }
        })
    });

    // 等待新创建的线程执行完成
    new_thread.join().unwrap();
    println!("Child thread is finish!");

    // 睡眠一段时间，看子线程创建的子线程是否还在运行
    thread::sleep(Duration::from_millis(100));
    //main 线程是程序的主线程，一旦结束，则程序随之结束，同时各个子线程也将被强行终止。
}

///线程屏障
///
///在rust 中 使用 barrier 可以让多个线程执行到某一个点后 再继续执行
pub fn run4() {
    // 创建一个预分配容量的线程句柄向量，容量为5
    // 使用 with_capacity 可以避免动态扩容带来的性能开销
    let mut handles = Vec::with_capacity(5);

    // 创建一个屏障(Barrier)，并包装在原子引用计数(Arc)中
    // Barrier::new(5) 表示需要5个线程都到达屏障点才能继续执行
    // Arc (Atomic Reference Counting) 允许在多个线程间安全地共享所有权
    let barrier = Arc::new(Barrier::new(5));

    // 创建5个线程
    for i in 0..5 {
        // 克隆屏障的Arc指针，每个线程获得一个独立的引用
        // Arc::clone() 只增加引用计数，不复制实际数据
        let b = barrier.clone();

        // 使用 thread::spawn 创建新线程
        handles.push(thread::spawn(move || {
            // 线程开始执行
            println!("线程 {} 到达屏障前", i);

            // 线程在此等待，直到所有5个线程都调用 wait() 方法
            // wait() 会阻塞当前线程，直到指定数量的线程都到达这个点
            b.wait();

            // 当所有线程都到达屏障后，所有线程同时继续执行
            println!("线程 {} 通过屏障后", i);
        }));
    }

    // 等待所有线程执行完成
    for han in handles {
        // join() 会阻塞当前线程，直到对应的子线程执行完毕
        // unwrap() 如果线程执行成功返回Ok，失败则panic
        han.join().unwrap();
    }

    // 当所有线程都join完成后，函数结束
}

///线程局部变量
///
///thread_local 宏可以初始化线程局部变量，然后在线程内部使用该变量的 with 方法获取变量值
///
///thread_local! {static Lo:RefCell<u32> = RefCell::new(1)};
pub fn run5() {
    thread_local! {static Lo:RefCell<u32> = RefCell::new(1)};
    Lo.with(|l| {
        assert_eq!(*l.borrow(), 1);
        *l.borrow_mut() = 2;
    });

    // 每个线程开始时都会拿到线程局部变量的FOO的初始值
    let t = thread::spawn(move || {
        Lo.with(|f| {
            assert_eq!(*f.borrow(), 1);
            *f.borrow_mut() = 3;
        });
    });

    // 等待线程完成
    t.join().unwrap();

    // 尽管子线程中修改为了3，我们在这里依然拥有main线程中的局部值：2
    Lo.with(|f| {
        assert_eq!(*f.borrow(), 2);
    });
}

pub fn run5_5() {
    // 使用 thread_local! 宏定义一个线程局部变量
    // 每个线程都会有自己独立的 foo 副本，初始值为 5
    // 使用 RefCell 来获得内部可变性，允许在不可变引用时修改值
    thread_local! {
        static foo: RefCell<i32> = RefCell::new(5)
    }

    // 在主线程中访问和修改 foo
    foo.with(|f| {
        // 验证初始值是否为 5
        assert_eq!(*f.borrow(), 5);
        // 修改主线程中的 foo 值为 6
        *f.borrow_mut() = 6;
    });

    // 创建 5 个新线程
    for i in 0..5 {
        thread::spawn(move || {
            // 在每个新线程中访问该线程自己的 foo 副本
            foo.with(|f| {
                // 这里断言会成功，因为每个新线程都会重新初始化自己的 foo 为 5
                // 而不是继承主线程修改后的值 6
                assert_eq!(*f.borrow(), 5);

                // 读取当前线程中 foo 的值
                let n = *f.borrow();

                // 修改当前线程中 foo 的值：原值 + 循环索引 i
                *f.borrow_mut() = n + i;

                // 打印当前线程的索引和修改后的 foo 值
                println!("i={}, foo={}", i, *f.borrow())
            });
        })
        .join()
        .unwrap(); // 立即等待当前线程完成，然后才创建下一个线程
        // 注意：这里使用 join() 意味着线程是顺序执行的，不是并发执行的
    }

    // 再次检查主线程中的 foo 值
    foo.with(|f| {
        // 输出仍然是 6，证明子线程对各自 foo 的修改不会影响主线程的 foo
        println!("最终主线程中 FOO = {}", *f.borrow()); // 仍然是 6，不受子线程影响
    });
}

///第三方库  thread-local
///
///它允许每个线程持有值的独立拷贝：
pub fn run6() {
    // 创建一个 ThreadLocal 实例，并用 Arc 包装以实现线程间共享
    // ThreadLocal 会为每个线程维护一个独立的 Cell::new(0) 副本
    let tls = Arc::new(ThreadLocal::new());
    let mut v = vec![]; // 用于存储线程句柄的向量

    // 创建多个线程
    for _ in 0..5 {
        // 克隆 Arc 指针，每个线程获得一个指向相同 ThreadLocal 的引用
        let tls2 = tls.clone();
        let handle = thread::spawn(move || {
            // 获取或初始化当前线程的线程局部变量
            // 如果当前线程还没有对应的值，则使用闭包创建一个新的 Cell::new(0)
            // 如果已有值，则直接返回该值的引用
            let cell = tls2.get_or(|| Cell::new(0));

            // 将当前线程的计数器值加1
            // Cell 提供了内部可变性，可以在不可变引用时修改值
            cell.set(cell.get() + 1);
        });
        v.push(handle); // 将线程句柄存入向量
    }

    // 等待所有线程执行完成
    for handle in v {
        handle.join().unwrap();
    }

    // 使用 Arc::try_unwrap 尝试获取底层的 ThreadLocal 对象
    // 因为所有线程都已结束，Arc 的引用计数为1，所以可以成功解包
    let tls = Arc::try_unwrap(tls).unwrap();

    // 将 ThreadLocal 转换为迭代器，遍历所有线程创建的计数器值
    // 注意：这里不一定有5个值，因为线程ID可能被回收重用
    let total = tls.into_iter().fold(0, |x, y| {
        // 打印累加过程中的中间值
        // x: 当前的累加和, y: 当前线程的计数器值
        println!("x: {}, y: {}", x, y.get());

        // 将当前线程的计数器值加到总和中
        x + y.get()
    });

    // 验证总和是否为5
    // 虽然线程ID可能被回收，但每个线程都执行了 cell.set(cell.get() + 1)
    // 所以总的增量应该是5
    assert_eq!(total, 5);
}

///条件控制线程的挂起和执行
///
/// 条件变量(Condition Variables)经常和 Mutex 一起使用，可以让线程挂起，直到某个条件发生后再继续执行：
/// Condvar  允许线程在等待某个条件成立时挂起，并在条件可能成立时被唤醒。
pub fn run7() {
    // 创建一个 Arc 包装的元组，包含：
    // - Mutex<bool>: 用于保护布尔状态的互斥锁
    // - Condvar: 条件变量，用于线程间通信
    let pair = Arc::new((Mutex::new(false), Condvar::new()));

    // 克隆 Arc 指针，用于传递给新线程
    // Arc 允许在多线程间安全地共享所有权
    let pair2 = pair.clone();

    let pair3 = pair.clone();
    // 创建新线程
    thread::spawn(move || {
        // 使当前线程暂停执行指定的时间
        // 参数：Duration::from_millis(10) 表示休眠 1000 毫秒
        thread::sleep(Duration::from_millis(1000));

        // 解引用 Arc 获取内部的锁和条件变量
        let (lock, cvar) = &*pair2;

        // 获取互斥锁，保护对共享状态的访问
        let mut started = lock.lock().unwrap();
        println!("子线程: 获取互斥锁，锁定状态{}", *started);

        // 修改共享状态：将 started 从 false 改为 true
        *started = true;

        // 通知一个等待的线程条件已改变
        // 这会唤醒在主线程中等待的 cvar.wait()
        //cvar.notify_one();
        cvar.notify_all();
        println!("子线程: 已修改状态并发送通知");
        // 锁在 started 离开作用域时自动释放
    });

    thread::spawn(move || {
        let (l, c) = &*pair3;
        let mut lc = l.lock().unwrap();
        println!("子线程2: 获取互斥锁,锁定状态{}", *lc);

        while !*lc {
            println!("子线程2: 获取互斥锁，锁定状态{}，进入等待状态...", *lc);
            // wait 方法会：
            // 1. 临时释放互斥锁（允许其他线程获取锁）
            // 2. 使当前线程进入睡眠状态
            // 3. 当收到 notify_one() 通知时被唤醒
            // 4. 重新获取互斥锁并返回
            lc = c.wait(lc).unwrap();
        }

        println!("子线程2: 获取互斥锁,锁定状态{}", *lc);
    });

    // 主线程继续执行
    // 获取对同一对锁和条件变量的引用
    let (lock, cvar) = &*pair;

    // 主线程获取互斥锁
    let mut started = lock.lock().unwrap();
    println!("主线程: 获取互斥锁，锁定状态{},开始等待条件", *started);

    // 使用 while 循环检查条件，防止虚假唤醒
    // 虚假唤醒：条件变量可能在没有收到通知的情况下意外唤醒
    while !*started {
        println!("主线程: 条件不满足，进入等待状态...");

        // wait 方法会：
        // 1. 临时释放互斥锁（允许其他线程获取锁）
        // 2. 使当前线程进入睡眠状态
        // 3. 当收到 notify_one() 通知时被唤醒
        // 4. 重新获取互斥锁并返回
        started = cvar.wait(started).unwrap();

        println!("主线程: 被唤醒，重新检查条件");
    }
}

///只被调用一次的函数
///
///use std::sync::Once;
///
///有时，我们会需要某个函数在多线程环境下只被调用一次，例如初始化全局变量，
///
///无论是哪个线程先调用函数来初始化，都会保证全局变量只会被初始化一次，随后的其它线程调用就会忽略该函数
pub fn run8() {
    // 使用 Once 来确保初始化代码只执行一次
    // 即使多个线程同时调用，也只有一个线程会执行初始化代码
    static init: Once = Once::new();

    // 使用 UnsafeCell 包装的全局变量
    // 由于多个线程会访问，需要内部可变性，但这里使用了 unsafe
    static mut var: i32 = 0;

    // 第一个线程：尝试初始化 var 为 1
    thread::spawn(move || {
        // call_once 确保闭包内的代码只会执行一次
        // 即使被多个线程调用，也只有一个线程会实际执行
        init.call_once(|| {
            unsafe {
                var = 1; // 设置全局变量为 1
                println!("线程1: 执行初始化，设置 var = 1");
            }
        });
        // 注意：这里使用了 join().unwrap() 会等待线程完成
        // 所以线程是顺序执行的，不是并发执行的
    })
    .join()
    .unwrap();

    // 第二个线程：也尝试初始化 var 为 1
    thread::spawn(move || {
        init.call_once(|| {
            unsafe {
                var = 1; // 这行代码不会执行，因为初始化已经完成
                println!("线程2: 执行初始化，设置 var = 1");
            }
        });
        // 由于第一个线程已经执行了初始化，这个闭包不会被执行
    })
    .join()
    .unwrap();

    // 第三个线程：尝试初始化 var 为 3
    thread::spawn(move || {
        init.call_once(|| {
            unsafe {
                var = 3; // 这行代码不会执行，因为初始化已经完成
                println!("线程3: 执行初始化，设置 var = 3");
            }
        });
        // 由于初始化已经在第一个线程中完成，这个闭包也不会执行
    })
    .join()
    .unwrap();

    // 打印最终的 var 值
    // 由于 Once 的保证，只有第一个线程的初始化代码实际执行了
    println!("var 值: {}", unsafe { var }); // 输出: var 值: 1

    /*
    主线程启动
      ↓
    创建线程1 → 执行 init.call_once() → 设置 var = 1 → 线程1结束
      ↓
    创建线程2 → 调用 init.call_once() → 发现已初始化 → 跳过闭包 → 线程2结束
      ↓
    创建线程3 → 调用 init.call_once() → 发现已初始化 → 跳过闭包 → 线程3结束
      ↓
    打印 var 值 = 1



         */
}

///消息通道
///
/// td::sync::mpsc   多发送者，单接收者
///
/// 其中mpsc是multiple producer, single consumer的缩写，代表了该通道支持多个发送者，但是只支持唯一的接收者。  
pub fn run9() {
    // 创建一个多生产者单消费者（MPSC）通道
    // s: Sender<T> - 发送端，可以有多个发送者（克隆后）
    // r: Receiver<T> - 接收端，只能有一个接收者
    let (s, r) = mpsc::channel();

    // 创建第一个线程：发送者线程
    thread::spawn(move || {
        // 将发送端 s 移动到线程中
        // 发送整数值 4 到通道中
        // send() 方法返回 Result<(), SendError<T>>
        // unwrap() 如果发送失败会 panic
        s.send(4).unwrap();
        // 发送完成后，发送端会被自动丢弃（drop）
        println!("发送者线程: 已发送值 4");
    });

    // 创建第二个线程：接收者线程
    thread::spawn(move || {
        // 将接收端 r 移动到线程中
        // recv() 方法会阻塞当前线程，直到从通道接收到值
        // 返回 Result<T, RecvError>
        let val = r.recv().unwrap();

        // 打印接收到的值
        println!("接收者线程: 接收到值 {}", val);

        // 接收完成后，接收端会被自动丢弃
    });

    // 注意：主线程会立即退出，不会等待子线程完成
    // 这可能导致程序在子线程完成前就结束
}

///非阻塞 消息获取  try_recv
///
/// try_recv尝试接收一次消息，该方法并不会阻塞线程，当通道中没有消息时，它会立刻返回一个错误：
pub fn run10() {
    // 创建一个多生产者单消费者（MPSC）通道
    // 用于在线程间传递 i32 类型的数据
    let (s, r) = mpsc::channel();

    // 创建第一个线程：生产者线程（无限发送数据）
    thread::spawn(move || {
        // 将发送端 s 移动到生产者线程中
        let mut i = 0; // 初始化计数器
        while true {
            // 无限循环，不断发送数据
            i = i + 1; // 计数器递增

            s.send(i).unwrap(); // 发送当前计数值到通道
            // 注意：这里没有延迟，会极快地发送数据
            // 可能导致接收端无法及时处理
        }
        // 发送端 s 在这里永远不会被丢弃，所以通道一直保持打开状态
    });

    // 创建第二个线程：消费者线程（尝试接收数据）
    thread::spawn(move || {
        // 将接收端 r 移动到消费者线程中
        while true {
            // 无限循环，不断尝试接收数据
            // 使用 try_recv() 非阻塞尝试接收数据
            // try_recv() 立即返回，不会等待
            println!("run10 {:?}", r.try_recv().unwrap());
            // 这里使用 unwrap() 会有问题，因为 try_recv() 可能返回错误
        }
    })
    .join() // 等待消费者线程完成（实际上永远不会完成，因为无限循环）
    .unwrap(); // 如果线程 panic 会在这里触发

    // 主线程会阻塞在 join() 上，永远不会执行到这里
}

///传输具有所有权的数据
pub fn run11() {
    let (s, r) = mpsc::channel();

    thread::spawn(move || {
        while true {
            let str = String::from("大王叫我来巡山");
            //str 所有权转移到send 中 后续的str 将不可用
            s.send(str).unwrap();
        }
    });

    thread::spawn(move || {
        // while true {
        //     let str = r.recv().unwrap();
        //     println!("str-{str}");
        // }
        loop {
            let str = r.recv().unwrap();
            println!("str-{str}");
        }
    });
}

///使用 for 进行循环接收
pub fn run12() {
    let (s, r) = mpsc::channel();

    thread::spawn(move || {
        let vals = vec![
            String::from("hi"),
            String::from("from"),
            String::from("the"),
            String::from("thread"),
        ];

        for val in vals {
            s.send(val).unwrap();
            thread::sleep(Duration::from_secs(1));
        }
    });

    thread::spawn(move || {
        for r_item in r {
            println!("Got: {}", r_item);
        }
    })
    .join()
    .unwrap();
}

///使用多发送者
pub fn run13() {
    let (s, r) = mpsc::channel();
    let s1 = s.clone();
    thread::spawn(move || {
        s.send(String::from("hi from raw s")).unwrap();
    });

    thread::spawn(move || {
        s1.send(String::from("hi from cloned s1")).unwrap();
    });

    thread::spawn(move || {
        for r_item in r {
            println!("Got: {}", r_item);
        }
    })
    .join()
    .unwrap();
}
///同步通道
pub fn run14() {
    // 创建一个同步通道（sync_channel），缓冲区大小为 0
    // 同步通道与异步通道的区别：
    // - 异步通道 (channel): 发送操作立即返回，不等待接收
    // - 同步通道 (sync_channel): 发送操作会阻塞，直到有接收者接收数据
    // 缓冲区大小 0 表示：发送者必须等待接收者准备好才能发送（ rendezvous 模式）
    let (s, r) = mpsc::sync_channel(0);

    // 创建第一个线程：发送者线程
    thread::spawn(move || {
        println!("发送之前");
        // 在同步通道中，send() 操作会阻塞
        // 直到有接收者调用 recv() 准备接收数据
        s.send(1).unwrap();
        // 这行代码会在接收者调用 recv() 后才执行
        println!("发送之后");
    });

    // 创建第二个线程：接收者线程
    thread::spawn(move || {
        println!("睡眠之前");
        // 睡眠 3 秒，模拟处理其他任务
        thread::sleep(Duration::from_secs(3));
        println!("睡眠之后");

        // 调用 recv() 接收数据
        // 此时发送者线程的 send() 调用才会完成
        println!("receive {}", r.recv().unwrap());
        // 接收完成后，发送者线程的 "发送之后" 才会被打印
    })
    .join()
    .unwrap(); // 等待接收者线程完成

    // 主线程会在这里继续执行
}

pub enum Fruit {
    Apple(u8),
    Orange(String),
}
///传输多种类型的数据
pub fn run15() {
    let (s, r): (Sender<Fruit>, Receiver<Fruit>) = mpsc::channel();

    s.send(Fruit::Orange("sweet".to_string())).unwrap();
    s.send(Fruit::Apple(2)).unwrap();

    for _ in 0..2 {
        match r.recv().unwrap() {
            Fruit::Apple(count) => println!("received {} apples", count),
            Fruit::Orange(flavor) => println!("received {} oranges", flavor),
        }
    }
}

/*
线程同步： 锁、 condvar 和信号量
在多线程编程中，同步性极其的重要，当你需要同时访问一个资源、控制不同线程的执行次序时，都需要使用到同步性。

消息传递的底层实际上也是通过共享内存来实现，两者的区别如下：
共享内存相对消息传递能节省多次内存拷贝的成本
共享内存的实现简洁的多
共享内存的锁竞争更多

消息传递类似一个单所有权的系统：一个值同时只能有一个所有者，如果另一个线程需要该值的所有权，需要将所有权通过消息传递进行转移。
而共享内存类似于一个多所有权的系统：多个线程可以同时访问同一个值。

 */

///mutex 互斥锁
/*Rc 指针是单线程指针，没有实现send 等特征
 pub fn run16(){

    let counter = Rc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Rc::clone(&counter);

        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();

            *num += 1;
        });
        handles.push(handle);
    }


    for handle in handles {
        handle.join().unwrap();
    }


    println!("Result: {}", *counter.lock().unwrap());
 }
*/
pub fn run16_16() {
    // 使用 Arc 替代 Rc
    // Arc (Atomic Reference Counting): 原子引用计数，线程安全版本
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    // 创建 10 个线程
    for _ in 0..10 {
        // 克隆 Arc 指针，增加原子引用计数
        let counter = Arc::clone(&counter);

        let handle = thread::spawn(move || {
            // 获取互斥锁
            let mut num = counter.lock().unwrap();

            // 修改共享数据
            *num += 1;

            println!("线程 {:?}: 增加计数器", thread::current().id());

            // 锁在这里自动释放
        });
        handles.push(handle);
    }

    // 等待所有线程完成
    for handle in handles {
        handle.join().unwrap();
    }

    // 输出最终结果
    println!("最终结果: {}", *counter.lock().unwrap());
    // 期望输出: 最终结果: 10
}

use lazy_static::lazy_static;
lazy_static! {
    static ref MUTEX1: Mutex<i64> = Mutex::new(0);
    static ref MUTEX2: Mutex<i64> = Mutex::new(0);
}

///死锁
pub fn run17() {
    // 定义两个全局互斥锁
    // 注意：在实际代码中这些需要在外部定义，例如：
    // static MUTEX1: Mutex<i64> = Mutex::new(0);
    // static MUTEX2: Mutex<i64> = Mutex::new(0);

    // 存放子线程句柄的向量
    let mut children = vec![];

    // 创建 2 个线程
    for i_thread in 0..2 {
        children.push(thread::spawn(move || {
            for _ in 0..1 {
                // 线程1（i_thread = 0）
                if i_thread % 2 == 0 {
                    // 第一步：锁住 MUTEX1
                    let guard: MutexGuard<i64> = MUTEX1.lock().unwrap();

                    println!("线程 {} 锁住了MUTEX1，接着准备去锁MUTEX2 !", i_thread);

                    // 当前线程睡眠一小会儿，等待线程2锁住MUTEX2
                    // 这个睡眠是关键，它让线程2有机会先获取 MUTEX2
                    thread::sleep(Duration::from_millis(10));

                    // 重要：在尝试获取第二个锁之前，显式释放第一个锁
                    drop(guard); // 使用完锁后要记得释放，否则就会产生死锁

                    // 第二步：去锁 MUTEX2（现在不会死锁，因为已经释放了 MUTEX1）
                    let guard = MUTEX2.lock().unwrap();
                    // 这里可以安全地使用 guard

                    // 线程2（i_thread = 1）
                } else {
                    // 第一步：锁住 MUTEX2
                    let _guard = MUTEX2.lock().unwrap();

                    // 重要：立即释放 MUTEX2，避免死锁
                    drop(_guard); // 使用完锁后要记得释放，否则就会产生死锁

                    println!("线程 {} 锁住了MUTEX2, 准备去锁MUTEX1", i_thread);

                    // 第二步：去锁 MUTEX1（现在不会死锁，因为已经释放了 MUTEX2）
                    let _guard = MUTEX1.lock().unwrap();
                    // 这里可以安全地使用 _guard
                }
            }
        }));
    }

    // 等待所有子线程完成
    for child in children {
        let _ = child.join(); // 忽略 join 的结果
    }

    println!("死锁没有发生");
}

///try_lock
///
/// 与lock方法不同，try_lock会尝试去获取一次锁，如果无法获取会返回一个错误，因此不会发生阻塞:
/// 在 Rust 标准库中，使用try_xxx都会尝试进行一次操作，如果无法完成，就立即返回，不会发生阻塞。例如消息传递章节中的try_recv以及本章节中的try_lock
pub fn run18() {
    // 存放子线程句柄的向量
    let mut children = vec![];

    // 创建 2 个线程
    for i_thread in 0..2 {
        children.push(thread::spawn(move || {
            for _ in 0..1 {
                // 线程0 (i_thread = 0)
                if i_thread % 2 == 0 {
                    // 第一步：使用 lock() 阻塞方式获取 MUTEX1
                    let guard: MutexGuard<i64> = MUTEX1.lock().unwrap();

                    println!("线程 {} 锁住了MUTEX1，接着准备去锁MUTEX2 !", i_thread);

                    // 睡眠 10ms，让线程1有机会获取 MUTEX2
                    thread::sleep(Duration::from_millis(10));

                    // 第二步：使用 try_lock() 非阻塞方式尝试获取 MUTEX2
                    // try_lock() 的特点：
                    // - 成功：返回 Ok(MutexGuard)
                    // - 失败：返回 Err(TryLockError) 而不是阻塞
                    let guard = MUTEX2.try_lock();
                    println!("线程 {} 获取 MUTEX2 锁的结果: {:?}", i_thread, guard);

                    // 注意：MUTEX1 的锁会在 guard 离开作用域时自动释放
                } else {
                    // 线程1 (i_thread = 1)
                    // 第一步：使用 lock() 阻塞方式获取 MUTEX2
                    let _guard = MUTEX2.lock().unwrap();

                    println!("线程 {} 锁住了MUTEX2, 准备去锁MUTEX1", i_thread);

                    // 睡眠 10ms，让线程0有机会获取 MUTEX1（但线程0已经持有 MUTEX1）
                    thread::sleep(Duration::from_millis(10));

                    // 第二步：使用 try_lock() 非阻塞方式尝试获取 MUTEX1
                    let guard = MUTEX1.try_lock();
                    println!("线程 {} 获取 MUTEX1 锁的结果: {:?}", i_thread, guard);

                    // 注意：MUTEX2 的锁会在 _guard 离开作用域时自动释放
                }
            }
        }));
    }

    // 等待所有子线程完成
    for child in children {
        let _ = child.join(); // 忽略 join 的结果
    }

    println!("死锁没有发生");
}

/*RwLock
RwLock（Reader-Writer Lock）允许多个读取者同时访问数据，但只允许一个写入者访问。这在读多写少的场景中能显著提高并发性能。
多个读取者：可以同时有多个读取线程
单个写入者：同一时间只能有一个写入线程
写者优先 或 读者优先：不同实现有不同的调度策略
线程安全：内部使用原子操作保证线程安全

使用RwLock你得操心几个问题：
读和写不能同时发生，如果使用try_xxx解决，就必须做大量的错误处理和失败重试机制
当读多写少时，写操作可能会因为一直无法获得锁导致连续多次失败(writer starvation)
RwLock 其实是操作系统提供的，实现原理要比Mutex复杂的多，因此单就锁的性能而言，比不上原生实现的Mutex
再来简单总结下两者的使用场景：

追求高并发读取时，使用RwLock，因为Mutex一次只允许一个线程去读取
如果要保证写操作的成功性，使用Mutex
不知道哪个合适，统一使用Mutex
需要注意的是，RwLock虽然看上去貌似提供了高并发读取的能力，但这个不能说明它的性能比Mutex高，事实上Mutex性能要好不少，后者唯一的问题也仅仅在于不能并发读取。

 */
pub fn run19() {
    // 创建一个线程安全的读写锁，保护一个 i32 类型的计数器
    // 使用 Arc (Atomic Reference Counting) 实现多线程间的共享所有权
    let counter = Arc::new(RwLock::new(0));

    // 存储所有线程句柄的向量
    let mut handles = vec![];

    // 创建 10 个读取者线程
    for i in 0..10 {
        // 克隆 Arc 指针，增加引用计数
        // 每个线程获得 counter 的一个新引用
        let counter = Arc::clone(&counter);

        let handle = thread::spawn(move || {
            // 获取读锁 - 允许多个线程同时读取
            // read() 返回 RwLockReadGuard，实现了 Deref trait
            let value = counter.read().unwrap();

            // 打印读取到的值
            // 由于 RwLockReadGuard 实现了 Deref，可以直接使用 *value
            println!("Thread {i} read the value {value}");

            // 读锁在 value 离开作用域时自动释放
            // 注意：这里没有立即释放锁，而是等到整个线程结束
        });
        handles.push(handle);
    }

    // 创建一个写入者线程
    // 使用独立的作用域来管理克隆
    {
        // 克隆 Arc 指针用于写入者线程
        let counter = Arc::clone(&counter);

        let handle = thread::spawn(move || {
            // 获取写锁 - 独占访问，会阻塞直到所有读锁释放
            // write() 返回 RwLockWriteGuard，允许修改数据
            let mut value = counter.write().unwrap();

            // 修改计数器值
            *value += 1;

            // 打印修改后的值
            println!("Thread wrote the value {value}");

            // 写锁在 value 离开作用域时自动释放
        });
        handles.push(handle);
    } // 这里的 counter 克隆离开作用域，减少引用计数

    // 等待所有线程完成
    // into_iter() 会消耗 handles 向量，获取所有权
    handles.into_iter().for_each(|handle| {
        // 等待每个线程结束
        // unwrap() 会传播线程中的 panic
        handle.join().unwrap()
    });

    // 打印最终结果
    // 再次获取读锁来读取最终值
    println!("Result: {}", *counter.read().unwrap());
}

/*
用条件变量(Condvar)控制线程的同步

*/
pub fn run20() {
    let flag = Arc::new(Mutex::new(false));
    let cond = Arc::new(Condvar::new());
    let cflag = flag.clone();
    let ccond = cond.clone();

    let hdl = thread::spawn(move || {
        let mut lock = cflag.lock().unwrap();
        let mut counter = 0;

        while counter < 3 {
            while !*lock {
                // wait方法会接收一个MutexGuard<'a, T>，且它会自动地暂时释放这个锁，使其他线程可以拿到锁并进行数据更新。
                // 同时当前线程在此处会被阻塞，直到被其他地方notify后，它会将原本的MutexGuard<'a, T>还给我们，
                // 即重新获取到了锁，同时唤醒了此线程。
                lock = ccond.wait(lock).unwrap();
            }

            *lock = false;

            counter += 1;
            println!("inner counter: {}", counter);
        }
    });

    let mut counter = 0;
    loop {
        thread::sleep(Duration::from_millis(1000));
        *flag.lock().unwrap() = true;
        counter += 1;
        if counter > 3 {
            break;
        }
        println!("outside counter: {}", counter);
        cond.notify_one();
    }
    hdl.join().unwrap();
    println!("{:?}", flag);
}

/*
线程同步：Atomic 原子类型与内存顺序
原子指的是一系列不可被 CPU 上下文交换的机器指令，这些指令组合在一起就形成了原子操作。
在多核 CPU 下，当某个 CPU 核心开始运行原子操作时，会先暂停其它 CPU 内核对内存的操作，以保证原子操作不会被其它 CPU 内核所干扰。
还有一点值得注意: 和Mutex一样，Atomic的值具有内部可变性，你无需将其声明为mut：

*/
// 定义常量：每个线程执行的加法次数
const N_TIMES: u64 = 10000000;
// 定义常量：线程数量
const N_THREADS: usize = 10;

// 静态原子变量，用于多线程间的安全计数
static R: AtomicU64 = AtomicU64::new(0);

// 函数：创建一个线程，执行指定次数的原子加法
fn add_n_times(n: u64) -> thread::JoinHandle<()> {
    thread::spawn(move || {
        // 循环 n 次，每次对原子变量 R 加 1
        for _ in 0..n {
            // 使用 Relaxed 内存序，只保证原子性，不保证内存顺序
            R.fetch_add(1, Ordering::Relaxed);
        }
    })
}

pub fn run21() {
    // 记录开始时间
    let s = Instant::now();

    // 预分配容量创建线程句柄向量
    let mut threads = Vec::with_capacity(N_THREADS);

    // 创建 N_THREADS 个线程
    for _ in 0..N_THREADS {
        threads.push(add_n_times(N_TIMES));
    }

    // 等待所有线程执行完成
    for thread in threads {
        thread.join().unwrap();
    }

    // 验证结果：总计数应该等于线程数 × 每个线程的执行次数
    assert_eq!(N_TIMES * N_THREADS as u64, R.load(Ordering::Relaxed));

    // 打印程序执行时间
    println!("{:?}", Instant::now().sub(s));
}

/*
内存顺序规则
Relaxed， 这是最宽松的规则，它对编译器和 CPU 不做任何限制，可以乱序

Release 释放，设定内存屏障(Memory barrier)，保证它之前的操作永远在它之前，但是它后面的操作可能被重排到它前面

Acquire 获取, 设定内存屏障，保证在它之后的访问永远在它之后，但是它之前的操作却有可能被重排到它后面，往往和Release在不同线程中联合使用

AcqRel, 是 Acquire 和 Release 的结合，同时拥有它们俩提供的保证。比如你要对一个 atomic 自增 1，同时希望该操作之前和之后的读取或写入操作不会被重新排序

SeqCst 顺序一致性， SeqCst就像是AcqRel的加强版，它不管原子操作是属于读取还是写入的操作，只要某个线程有用到SeqCst的原子操作，
线程中该SeqCst操作前的数据操作绝对不会被重新排在该SeqCst操作之后，且该SeqCst操作后的数据操作也绝对不会被重新排在SeqCst操作前。


AtomicIsize 和 AtomicUsize 是与单线程 isize 类型和 usize 类型对应的共享整数类型。
AtomicI8、AtomicI16、AtomicI32、AtomicI64 及其无符号变体（如 AtomicU8）是共享整数类型，对应于单线程中的类型 i8、i16 等。
AtomicBool 是一个共享的 bool 值。
AtomicPtr 是不安全指针类型 *mut T 的共享值。

Load 、Store: 存取值
Fetch-and-Modify: 获取并修改
Compare-and-Exchange: 比较并交换

*/
pub fn run22() {
    let num_done = AtomicUsize::new(0);

    let main_thread = thread::current();

    thread::scope(|s| {
        s.spawn(|| {
            for i in 0..100 {
                thread::sleep(Duration::from_millis(10));
                num_done.store(i + 1, std::sync::atomic::Ordering::Relaxed); // store 存储
                main_thread.unpark();
            }
        });

        loop {
            let n = num_done.load(std::sync::atomic::Ordering::Relaxed); // load 获取
            if n == 100 {
                break;
            }
            println!("Working... {n}/100 done");
            thread::park_timeout(Duration::from_millis(1));
        }
    });
    println!("Done!");
}

pub fn run23() {
    let mut threads = Vec::with_capacity(10);

    for i in 0..10 {
        threads.push(thread::spawn(move || {
            for j in 0..10 {
                R.fetch_add(1, Ordering::Relaxed);
            }
        }));
    }

    for i in threads {
        i.join().unwrap();
    }

    assert_eq!(100, R.load(Ordering::Relaxed));
    println!("{}", R.load(Ordering::Relaxed));
}

static AB: AtomicBool = AtomicBool::new(false);
pub fn run24() {
    let mut threads = Vec::with_capacity(10);
    for i in 0..10 {
        threads.push(thread::spawn(move || {
            for j in 0..10 {
                let bo = AB.load(Ordering::Relaxed);
                AB.store(!bo, Ordering::Relaxed);
                println!(
                    "thread {},value {},ABVal {}",
                    i,
                    j,
                    AB.load(Ordering::Relaxed)
                );
            }
        }));
    }

    for i in threads {
        i.join().unwrap();
    }

    println!("{}", R.load(Ordering::Relaxed));
}
/*************************/
// 静态可变全局变量，用于在线程间共享数据
// 使用 unsafe 是因为多个线程可能同时访问
static mut DATA: u64 = 0;

// 原子布尔值，用于标识数据是否准备就绪
// 使用原子操作确保线程安全
static READY: AtomicBool = AtomicBool::new(false);

// 重置函数，在每次循环开始时调用
fn reset() {
    unsafe {
        DATA = 0; // 重置数据为0
    }
    READY.store(false, Ordering::Relaxed); // 使用宽松排序重置就绪标志
}

// 生产者线程函数
fn producer() -> thread::JoinHandle<()> {
    thread::spawn(move || {
        unsafe {
            DATA = 100; // A: 写入数据
        }
        // B: Release 内存排序确保：
        // - 在store(true)之前的所有写操作（包括DATA=100）对其他线程可见
        // - 防止编译器和CPU重排序，确保DATA=100在READY=true之前完成
        READY.store(true, Ordering::Release); // B: 发布就绪标志
    })
}

// 消费者线程函数
fn consumer() -> thread::JoinHandle<()> {
    thread::spawn(move || {
        // C: Acquire 内存排序确保：
        // - 当读取到READY=true时，能看见所有在Release之前发生的写操作
        // - 循环等待直到数据准备就绪
        while !READY.load(Ordering::Acquire) {} // C: 等待就绪标志

        // D: 由于Acquire-Release配对，这里保证能看到DATA=100的写入
        // 如果内存排序正确，断言应该总是成功
        assert_eq!(100, unsafe { DATA }); // D: 验证数据
    })
}

pub fn run25() {
    // 无限循环测试，验证同步机制的正确性
    loop {
        reset(); // 每次循环前重置状态

        let t_producer = producer(); // 创建生产者线程
        let t_consumer = consumer(); // 创建消费者线程

        t_producer.join().unwrap(); // 等待生产者完成
        t_consumer.join().unwrap(); // 等待消费者完成

        // 如果断言失败，程序会panic
        // 如果运行正常，这个循环会一直继续
    }
}

pub fn run26() {
    let spinlock = Arc::new(AtomicUsize::new(1));

    let spinlock_clone = Arc::clone(&spinlock);
    let thread = thread::spawn(move || {
        spinlock_clone.store(0, Ordering::SeqCst);
    });

    // 等待其它线程释放锁
    while spinlock.load(Ordering::SeqCst) != 0 {
        hint::spin_loop();
    }

    if let Err(panic) = thread.join() {
        println!("Thread had an error: {:?}", panic);
    }
}





/*

Send 和 Sync 

实现Send的类型可以在线程间安全的传递其所有权

实现Sync的类型可以在线程间安全的共享(通过引用)


*****************************
这里还有一个潜在的依赖：一个类型要在线程间安全的共享的前提是，指向它的引用必须能在线程间传递。因为如果引用都不能被传递，我们就无法在多个线程间使用引用去访问同一个数据了。
由上可知，若类型 T 的引用&T是Send，则T是Sync。
简而言之：Send 是 Sync 的前提，也就是，传递是共享的前提。
而共享是通过引用去共享的，那么如果一个类型 T 的引用 &T 是能传递的，说明类型 T 是可以能共享的。
*****************************

实现Send的类型可以在线程间安全的传递其所有权, 实现Sync的类型可以在线程间安全的共享(通过引用)
绝大部分类型都实现了Send和Sync，常见的未实现的有：裸指针、Cell、RefCell、Rc 等
可以为自定义类型实现Send和Sync，但是需要unsafe代码块
可以为部分 Rust 中的类型实现Send、Sync，但是需要使用newtype，例如文中的裸指针例子
*/

pub  fn run27(){
    let t = RwLock::new(0);
}















pub fn Run() {
    //run1();
    //run2();
    //run3();
    //run4();
    //run5();
    //run5_5();
    //run6();
    //run7();
    //run8();
    //run9();
    //run10();
    //run11();
    //run12();
    //run13();
    //run14();
    //run15();
    //run16();
    //run16_16();
    //run17();
    //run18();
    //run19();
    //run20();
    //run21();
    //run22();
    //run23();
    //run24();
    //run25();
    run26();
}
